package com.zw.cloud.mybatis.plus.event;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

@Component
@Slf4j
public class EventPublisher {
    @Resource
    private AsyncEventBus asyncEventBus;
    @Resource
    private EventBus syncEventBus;

    /**
     * 发布事件
     *
     * @param event 事件
     */
    public void publish(BaseEvent<?> event) {
        if (event.getType() == 1) {
            // 服务内消息
            log.info("[EventPublisher][publish]开始发布进程内事件: {}", JSON.toJSONString(event, JSONWriter.Feature.WriteMapNullValue));
            if (event.async) {
                // 异步
                /**
                 * 1.异步执行，事件发送方异步发出事件，不会等待事件消费方是否收到，直接执行自己后面的代码。
                 * 2.在定义AsyncEventBus时，构造函数中会传入一个线程池。事件消费方收到异步事件时，消费方会从线程池中获取一个新的线程来执行自己的任务。
                 * 3.同一个事件的多个订阅者，它们的注册顺序跟接收到事件的顺序上没有任何联系，都会同时收到事件，并且都是在新的线程中，异步并发的执行自己的任务。
                 */
                asyncEventBus.post(event);
            } else {
                // 同步
                /**
                 * EventBus
                 * - 1.同步执行，事件发送方在发出事件之后，会等待所有的事件消费方执行完毕后，才会回来继续执行自己后面的代码。
                 * - 2.事件发送方和事件消费方会在同一个线程中执行，消费方的执行线程取决于发送方。
                 * - 3.同一个事件的多个订阅者，在接收到事件的顺序上面有不同。谁先注册到EventBus的，谁先执行，如果是在同一个类中的两个订阅者一起被注册到EventBus的情况，收到事件的顺序跟方法名有关。
                 *
                 */
                syncEventBus.post(event);
            }
        }
    }

    public void publish(List<? extends BaseEvent> eventList) {
        if (CollectionUtils.isEmpty(eventList)) {
            return;
        }
        eventList.forEach(this::publish);
    }
}
